/**
 * Copyright 2012 ibiblio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ibiblio.terasaur.item

import org.ibiblio.terasaur.user.User
import org.ibiblio.terasaur.item.Item
import org.ibiblio.terasaur.bt.Torrent
import org.ibiblio.terasaur.controller.ParamsHelper
import org.ibiblio.terasaur.search.DateHelper
import org.ibiblio.terasaur.ui.UrlHelper
import org.ibiblio.terasaur.item.PermissionHelper
import org.ibiblio.terasaur.controller.ItemMixin
import org.ibiblio.terasaur.controller.ApiMixin
import org.joda.time.DateTime
import org.grails.plugins.springsecurity.service.acl.AclUtilService
import org.springframework.security.access.AccessDeniedException
import grails.converters.JSON

@Mixin([ItemMixin, ApiMixin])
class ItemApiController {
    boolean _flushTransactions = false // Option for unit testing
    def springSecurityService // injected
    def itemService // injected
    def aclUtilService // injected
    static ParamsHelper _paramsHelper = new ParamsHelper()
    static UrlHelper urlHelper = new UrlHelper()
    static PermissionHelper permissionHelper = new PermissionHelper()

    def show = {
        Map responseMap = [:]
        try {
            apiAuthenticationCheck()
            def item = getItemInstance()
            if (item) {
                boolean canEdit = canEditItem(item)
                if (canEdit) {
                    responseMap.item = itemToMap(item, canEdit)
                    responseMap.item.identifier = urlHelper.serverUrl() + urlHelper.canonicalLink(item, 'show')
                } else {
                    responseMap.error = message(code: 'item.permission.denied.message')
                }
            } else {
                responseMap.error = message(code: 'item.not.found.message')
            }
        } catch (AccessDeniedException e) {
            responseMap.error = e.message
        } catch (Exception e) {
            log.error('Item API show exception (' + e.class.name + '): ' + e.message)
            responseMap.error = 'Unknown error'
        }
        render(responseMap as JSON)
    }

    def save = {
        Map responseMap = [:]
        try {
            apiAuthenticationCheck()
            Map saveParams = _getItemSaveParams()
            Map result = itemService.save(saveParams, springSecurityService.currentUser)
            responseMap.success = result['success']

            if (result['success']) {
                responseMap.item = itemToMap(result['item'], true)
                responseMap.item.identifier = urlHelper.serverUrl() + urlHelper.canonicalLink(result['item'], 'show')
            } else {
                responseMap.error = message(code:getItemSaveErrorCode(result['item']))
                if (result['item'].errors.hasFieldErrors()) {
                    responseMap.fieldErrors = getItemFieldErrors(result['item'])
                }
            }
        } catch (AccessDeniedException e) {
            responseMap.error = e.message
        } catch (Exception e) {
            log.error('Item API save exception (' + e.class.name + '): ' + e.message)
            responseMap.error = 'Unknown error'
        }
        render(responseMap as JSON)
    }

    /**
     * Update an existing item.  Tied to http PUT request.
     */
    def update = {
        Map responseMap = [:]
        try {
            apiAuthenticationCheck()
            Item item = _getItemInstanceFromJson()
            if (item) {
                Map saveParams = _getItemSaveParams()
                boolean success = itemService.update(item, saveParams)
                responseMap.success = success
                if (success) {
                    responseMap.item = itemToMap(item, true)
                    responseMap.item.identifier = urlHelper.serverUrl() + urlHelper.canonicalLink(item, 'show')
                } else {
                    responseMap.error = message(code:getItemSaveErrorCode(item))
                    if (item.errors.hasFieldErrors()) {
                        responseMap.fieldErrors = getItemFieldErrors(item)
                    }
                }
            } else {
                responseMap.error = message(code:'item.not.found.message')
            }
        } catch (AccessDeniedException e) {
            responseMap.error = e.message
        } catch (Exception e) {
            log.error('Item API save exception (' + e.class.name + '): ' + e.message)
        }
        render(responseMap as JSON)
    }

    /**
     * Helpers
     */
    private Map _getItemSaveParams() {
        Map saveParams
        if (request.JSON) {
            saveParams = [
                title: request.JSON.title.toString(),
                description: request.JSON.description.toString(),
                language: request.JSON.language.toString(),
                type: request.JSON.type.toString(),
                published: request.JSON.published.toString(),
                license: request.JSON.license.toString(),
                collection: request.JSON.collection.toString()
                ]
        }
        return saveParams
    }

    private Item _getItemInstanceFromJson() {
        Item item
        try {
            // TODO: test invalid item id
            Long itemId = Long.parseLong(request.JSON.id)
            item = getItemInstanceForId(itemId)
        } catch (Exception e) { }
        return item
    }

}
